<?php
require_once "interface/Gi_Dispatcher_Interface.php";
require_once "Gi_Controller_Front.php";
include_once "Gi_Request.php";
include_once "Gi_Loader.php";
abstract class Gi_Dispatcher_Abstract implements Gi_Dispatcher_interface {
  private $_request;
  
  private $_controller_directory = "controllers";
  
  /**
  * @var Gi_Controller_Front
  */
  private $_front_controller =  null;
  
  public function __construct () {
    $this->_front_controller = Gi_Controller_Front::get_instance(); 
    return $this;
  }
  
  /**
  * @desc Entrega el objeto request al dispatcher
  * @var Gi_Request el objeto Request
  */
  public function set_request (Gi_Request_Interface $request) {
    $this->_request = $request;
    return $this;
  }
  
  /**
  * @desc Obtiene el request que utliza el dispatcher
  */
  public function get_request () {
    if ($this->_request !== null)
      return $this->_request;
    throw new Exception("EL objeto request no se ha definido aun");
  }
  
  /**
  * @desc para indicar en que directorio estan los action controllers
  */
  public function set_controller_direcory ($dir) {
    if (is_string($dir)){
      $this->_controller_directory = $dir;
      return $this;
    }
    
    throw new Exception("el controller directory debe ser un string");
  }
  
  /**
  * @desc obtiene el controller directory
  */
  public function get_controller_directory ($module = false) {
    if ($module) {
      if ($this->_controller_directory !== null)
        return $module . DIRECTORY_SEPARATOR . $this->_controller_directory;
      throw new Exception("el controller directory no ha sido definido todavia");
    }
    else {
      if ($this->_controller_directory !== null)
        return $this->_controller_directory;
      throw new Exception("el controller directory no ha sido definido todavia");
    }
  }
  
  /**
  * @desc Obtiene el nombre de la clase controller actual
  * @var el nombre del controller
  */
  private function get_class_name ($controller) {
    $name = strtolower($controller);
    $name = ucfirst($name);
      return $name . "_Controller";
  }
    
  /**
  * @desc obtiene el del metodo action actuial
  * @var el nombre del action
  */
  private function get_method_name ($action) {
    $name = strtolower($action);
    return $action . "_action";
  }
  
  /**
  * @todo dar soporte para despachar multiples actions en el mismo request
  * @desc despacha la request actual
  */
  public function dispatch () {
    //obtenemos la request
    $request = $this->get_request();
    
    /**
    * @desc dispatch loop
    */
    
    while (!$request->is_dispatched()) {
      $request->set_despatched();
      //obtenemos el modulo
      $module = $request->get_module();
      //obtenemos el controller
      $controller = $request->get_controller();
      //obtenemos el action
      $action = $request->get_action();
      //obtenemos los parametros
      $params = $request->get_params();
  
      //obtenemos nombre de clases y methodos
      $class = $this->get_class_name($controller);
      
      if ($module) {
        $class = ucfirst($module) . "_" . $class;
      }
      
      $method = $this->get_method_name($action);
    
      //cargamos la clase
      $dir = $this->_front_controller->get_app_dir() . DIRECTORY_SEPARATOR . $this->get_controller_directory($module);
    
      Gi_Loader::load_class($class,$dir,$module);
    
      //instanciamos
      $instance = new $class ($request);
    
      //despachamos
      $instance->pre_dispatch();
      $instance->dispatch($method);
      $instance->post_dispatch();
    }
    return $this;  
  }
}
